// tspcluster - Traveling Salesman Problem
// Copyright (C) 2006  Frederik Carlier
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

using System;
using System.Collections.Generic;
using System.Text;

namespace UGent.Tsp
{
    /// <summary>
    /// Does a cyclic permutation of the cities between i and i + n
    /// </summary>
    [HasParameter(true, 24)]
    public class Swap321 : ISwapper
    {
        private const int DefaultCount = 5;

        #region Constructors
        public Swap321(Route route)
            : this(route, DefaultCount)
        {
        }

        public Swap321(Route route, int count)
        {
            if (count < 1)
                throw new ArgumentOutOfRangeException("count");

            this.route = route;
            this.count = count;
            this.random = new Random();
        }
        #endregion

        #region Properties
        // The two cities that will be swapped.
        private int start;
        private int proposed;
        private int accepted;
        private Random random;

        public int ProposedMoves
        {
            get { return proposed; }
        }

        public int AcceptedMoves
        {
            get { return accepted; }
        }

        private Route route;
        public IRoute Route
        {
            get { return route; }
        }

        private int count;
        public int Count
        {
            get
            {
                return count;
            }
        }
        #endregion

        #region Methods
        public void Generate()
        {
            start = random.Next(Route.Map.CityCount - 1);
            proposed++;
        }

        public void Do()
        {
            route.PermutateCyclic(this.start, this.start + count);
            accepted++;
        }

        public double GetDelta()
        {
            double delta = 0;

            delta = delta - route.GetDistance(start - 1, start);
            delta = delta - route.GetDistance(start, start + 1);
            delta = delta - route.GetDistance(start + count, start + count + 1);

            delta = delta + route.GetDistance(start - 1, start + 1);
            delta = delta + route.GetDistance(start + count, start);
            delta = delta + route.GetDistance(start, start + count + 1);

            return delta;
        }
        #endregion
    }
}
